import common from "shared/component/common/common"
import Log4R from "../log/Log4R";
import { ColiGroup } from "shared/enums/ColiGroup";
const _RootAttName = "RootRigAttachment";
const runService = game.GetService('RunService')
export interface CharacterInsModel extends Model {
    /**
     * 记录角色类型
     */
    characterId?: StringValue
    Humanoid?: Humanoid
    HumanoidRootPart?: Part
}
function getRootAttName() {
    return _RootAttName
}
const loginfo = Log4R.getLog('info')
/** 创建角色骨架 */
function createCharacter(path: string) {
    const characterFolder = game.GetService('ServerStorage').FindFirstChild('characters');
    if (characterFolder) {
        const model = common.getByPath(path, characterFolder) as Instance | undefined;
        if (model?.IsA('Model')) {
            return model.Clone();
        }
    }

}
/** 移动角色到part */
function posCharacter(humanoid: Humanoid, mon: Part) {
    const model = humanoid.Parent;
    if (model?.IsA('Model')) {
        const humanoidRootPart = model.PrimaryPart;
        if (!humanoidRootPart?.IsA('Part')) return
        const bornYAdd = (- mon.Size.Y / 2) + (humanoid?.HipHeight || 0)
            + humanoidRootPart.Size.Y / 2 + 0.1;
        // loginfo?.info('bornYAdd', bornYAdd)
        humanoidRootPart.CFrame = (
            mon.CFrame.add(new Vector3(0, bornYAdd, 0)))
        return humanoidRootPart.CFrame;
    }

}
/** 改变总重量 */
function changeTotalMass(model: Model, G: number) {
    let g = 0;
    model.GetChildren().forEach(c => {
        if (c.IsA('BasePart')) {
            // print('cp', c.CustomPhysicalProperties)
            g += c.Mass
        }
    })
    model.GetChildren().forEach(c => {
        if (c.IsA('BasePart')) {
            const d = c.CustomPhysicalProperties?.Density || 0.7
            if (c.Name === 'UpperTorso') {
                const pp = new PhysicalProperties(d * G / g, 0, 0, 0, 0);
                c.CustomPhysicalProperties = pp
            } else {
                const pp = new PhysicalProperties(d * G / g, 0, 0, 0, 0);
                c.CustomPhysicalProperties = pp
            }

        }
    })

}
export function setFrameInterval(callback: (framenow: number, t?: number, s?: number) => void, frameLife: number, lastFrame?: () => void) {
    // print(debug.traceback('setFrameInterval'))
    let framenow = 0
    const connect = runService.Stepped.Connect((t, s) => {
        // print('setFrameInterval', t, s)
        callback(framenow++, t, s);
        if (frameLife < 0) return
        frameLife--;
        if (!frameLife) {
            if (lastFrame) lastFrame()
            if (connect) connect.Disconnect();
        } else {
            return
        }
    })
    return connect
}
const rotateInv = ['Slime']
const rotateRootTaskMap = new Map<Instance, RBXScriptConnection>()
function rotateRoot(body: CharacterInsModel, vector: Vector3, life = 15, angle = 60, r = false) {
    // loginfo?.info('rotateRoot,vector', vector)
    // life = math.floor(life / 2)
    /** 顶固的物体不摇摆只震动 */
    const anchored = body.HumanoidRootPart?.Anchored
    // loginfo?.info('rotate')
    if (!typeIs(angle, 'number')) {
        angle = 60
    }
    // const cid = body.characterId?.Value;
    // if (cid) {
    //     if (rotateInv.find(c => c === cid)) {
    //         angle = -angle
    //     }
    // }

    let upperTorso = body.FindFirstChild('UpperTorsoEx') as MeshPart;
    if (!upperTorso)
        upperTorso = body.FindFirstChild(Enum.BodyPartR15.UpperTorso.Name) as MeshPart;
    let LowerTorso = body.FindFirstChild('LowerTorso') as MeshPart;
    if (!LowerTorso)
        LowerTorso = body.FindFirstChild(Enum.BodyPartR15.LowerTorso.Name) as MeshPart;
    if (!upperTorso || !LowerTorso) return
    const motor = upperTorso.FindFirstChildOfClass('Motor6D');

    const bsc = upperTorso.FindFirstChildOfClass('BallSocketConstraint');
    if (bsc) bsc.MaxFrictionTorque = 0;
    const lmotor = LowerTorso.FindFirstChildOfClass('Motor6D');
    if (!motor || !lmotor) return

    // const baseCframe = motor.Transform;
    const u = upperTorso.CFrame.VectorToObjectSpace(vector.Unit).mul(-1);
    // const u = vector.Unit;
    // const frame = new CFrame(motor.Transform.Position)
    //     .mul(CFrame.Angles(0, 0, 0))
    // print('-----', u.Z, u.Z * -90, math.rad(u.Z * -90))
    const frame = new CFrame(motor.Transform.Position)
    rotateRootTaskMap.get(body)?.Disconnect();
    // const realTime = life * envconfig.SPF
    let passTime = 0;
    /**
     * 震动标志位
     */
    let shakeUp = true;
    const shakeDirect = new Vector3(0, 0.3, 0);
    let shakeCount = 0;
    let lastShakeTime = 0;
    const defaultLmotoTransform = lmotor.Transform;
    let lastLmotoTransform: CFrame | undefined;
    const stepMethod = setFrameInterval((keyframe, t, s) => {
        passTime += s || 0

        keyframe = math.floor(passTime / 0.1);
        // print('keyframe', oldKeyframe, keyframe, life)
        if (keyframe >= life) {
            stepMethod.Disconnect()
            return
        }
        keyframe = keyframe - 5
        if (keyframe < 0) {
            keyframe = 0
        }
        const ad = angle * (life - keyframe) / life
        if (r) {
            lmotor.Transform = frame
                // .mul(CFrame.Angles(math.rad(90), 0, 0))
                .mul(CFrame.Angles(math.rad(u.Z * -1 * ad / 3), 0, 0))
                .mul(CFrame.Angles(0, 0, math.rad(u.X * ad / 3)));
            motor.Transform = frame
                // .mul(CFrame.Angles(math.rad(90), 0, 0))
                .mul(CFrame.Angles(math.rad(math.clamp(u.Z * ad, -360, 30)), 0, 0))
                .mul(CFrame.Angles(0, 0, math.rad(math.clamp(u.X * -1 * ad, -30, 30))));
        } else {
            if (shakeCount < 3) {
                if ((passTime - lastShakeTime > 0.033)) {
                    lastShakeTime = passTime
                    if (shakeUp) {
                        lastLmotoTransform = defaultLmotoTransform.add(shakeDirect)
                    } else {
                        lastLmotoTransform = defaultLmotoTransform.add(shakeDirect.mul(-1))
                    }

                    shakeUp = !shakeUp
                    shakeCount++
                }
                if (lastLmotoTransform)
                    lmotor.Transform = lastLmotoTransform
            }

            if (!anchored)
                motor.Transform = frame
                    // .mul(CFrame.Angles(math.rad(90), 0, 0))
                    .mul(CFrame.Angles(math.rad(math.clamp(u.Z * -1 * ad, -360, 30)), 0, 0))
                    .mul(CFrame.Angles(0, 0, math.rad(math.clamp(u.X * ad, -30, 30))));
        }

        // print('--', frame)
    }, life, () => {
        if (anchored) {
            lmotor.Transform = defaultLmotoTransform;
        }
        rotateRootTaskMap.delete(body)
    });
    rotateRootTaskMap.set(body, stepMethod)

}
/** 获取角色逻辑Cframe */
function getCharacterLogicCframe(characterEntity: Ctn.character.CharacterEntity) {
    if (!characterEntity.character) return
    const orientation = characterEntity.character.HumanoidRootPart.AlignOrientation.CFrame.ToOrientation()
    const objectCframe = new CFrame(characterEntity.character.LowerTorso.CFrame.Position).mul(CFrame.fromOrientation(orientation[0], orientation[1], orientation[2]))
    return objectCframe
}
/** 获取角色逻辑Cframe */
function noCollisionUppertorso(characterEntity: Ctn.character.CharacterEntity, nocollision: boolean) {
    if (!characterEntity.character?.UpperTorso) return
    if (nocollision) {
        characterEntity.character.UpperTorso.CollisionGroup = ColiGroup.playerHumanRootPartDodge
    } else {
        characterEntity.character.UpperTorso.CollisionGroup = ColiGroup.playerHumanRootPart
    }

}
const characterTools = {
    noCollisionUppertorso,
    getCharacterLogicCframe,
    rotateRoot,
    getRootAttName,
    createCharacter,
    posCharacter,
    changeTotalMass
}


export default characterTools;